//! Rust bsp 定义
//!
//! 板子的 bsp 定义, 目前包括 cpu 数量定义, 内存范围定义, 控制台定义, 中断控制器定义.

use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{parse_macro_input, ItemStatic};

/// 定义 cpu 数量
#[proc_macro_attribute]
pub fn define_cpus(_: TokenStream, input: TokenStream) -> TokenStream {
    let f = parse_macro_input!(input as ItemStatic);

    quote!(
        #[export_name = "__NR_CPUS"]
        #f
    )
    .into()
}

/// 定义内存范围
#[proc_macro_attribute]
pub fn define_memrange(_: TokenStream, input: TokenStream) -> TokenStream {
    let f = parse_macro_input!(input as ItemStatic);

    quote!(
        #[export_name = "__MEMRANGE"]
        #f
    )
    .into()
}

/// 定义控制台
#[proc_macro_attribute]
pub fn define_console(_: TokenStream, input: TokenStream) -> TokenStream {
    let f = parse_macro_input!(input as ItemStatic);

    let name = Ident::new(&format!("{}", f.ident), Span::call_site());

    quote!(
        #f

        #[export_name = "__console_init"]
        #[doc(hidden)]
        pub unsafe fn console_init() {
            let mut lock = #name.lock_irq_save();
            use seminix::drivers::console::ConsoleImpl;
            lock.init();
        }

        #[export_name = "__console_output"]
        #[doc(hidden)]
        pub unsafe fn console_output(args: core::fmt::Arguments<'_>) {
            let mut lock = #name.lock_irq_save();
            use core::fmt::Write;
            lock.write_fmt(args).unwrap();
        }
    )
    .into()
}

/// 定义中断控制器
#[proc_macro_attribute]
pub fn define_irqchip(_: TokenStream, input: TokenStream) -> TokenStream {
    let f = parse_macro_input!(input as ItemStatic);

    let name = Ident::new(&format!("{}", f.ident), Span::call_site());

    quote!(
        #f

        extern crate alloc;
        use alloc::string::String;
        use seminix::irq::IrqchipImpl;
        #[export_name = "__irqchip_name"]
        #[doc(hidden)]
        pub unsafe fn irqchip_name() -> String {
            String::from(#name.name())
        }

        #[export_name = "__irq_disable"]
        #[doc(hidden)]
        pub unsafe fn irq_disable(hwirq: u32) {
            #name.irq_disable(hwirq);
        }

        #[export_name = "__irq_enable"]
        #[doc(hidden)]
        pub unsafe fn irq_enable(hwirq: u32) {
            #name.irq_enable(hwirq);
        }

        #[export_name = "__irq_set_type"]
        #[doc(hidden)]
        pub unsafe fn irq_set_type(hwirq: u32, irq_type: seminix::irq::IrqType) -> seminix::irq::Result<()> {
            #name.irq_set_type(hwirq, irq_type)
        }

        #[export_name = "__irq_set_affinity"]
        #[doc(hidden)]
        pub unsafe fn irq_set_affinity(hwirq: u32, cpumask: usize) -> seminix::irq::Result<()> {
            #name.irq_set_affinity(hwirq, cpumask)
        }

        #[export_name = "__irq_get_irqchip_state"]
        #[doc(hidden)]
        pub unsafe fn irq_get_irqchip_state(hwirq: u32, which: &seminix::irq::IrqchipIrqState) -> seminix::irq::Result<bool> {
            #name.irq_get_irqchip_state(hwirq, which)
        }

        #[export_name = "__irq_set_irqchip_state"]
        #[doc(hidden)]
        pub unsafe  fn __irq_set_irqchip_state(hwirq: u32, which: &seminix::irq::IrqchipIrqState, state: bool) -> seminix::irq::Result<()> {
            #name.irq_set_irqchip_state(hwirq, which, state)
        }

        #[export_name = "__send_ipi"]
        #[doc(hidden)]
        pub unsafe fn send_ipi(hwirq: u32, cpumask: usize) {
            #name.send_ipi(hwirq, cpumask);
        }

        #[export_name = "__send_ipi_one"]
        #[doc(hidden)]
        pub unsafe fn send_ipi_one(hwirq: u32, cpu: usize) {
            #name.send_ipi_one(hwirq, cpu);
        }

        #[export_name = "__handle_irqchip_irq"]
        #[doc(hidden)]
        pub unsafe fn handle_irqchip_irq() {
            #name.handle_irq();
        }

        #[export_name = "__irq_init"]
        #[doc(hidden)]
        pub unsafe fn irq_init() {
            #name.init();
        }

        #[export_name = "__irq_init_cpu"]
        #[doc(hidden)]
        pub unsafe fn irq_init_cpu() {
            #name.init_cpu();
        }
    )
    .into()
}
